package it.pdm.mep;


import it.mediaplayer.mep.R;

import java.io.IOException;

import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.google.api.client.googleapis.GoogleHeaders;
import com.google.api.client.googleapis.json.JsonCParser;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.client.util.DateTime;
import com.google.api.client.util.Key;

import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;

import android.os.AsyncTask;
import android.os.Bundle;

import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.AdapterView;

import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;


public class MediaPlayerActivity extends ListActivity  {

	private final static int FILE_CHOOSER_MUSIC = 49202; //indica la Intent per la scelta della musica in locale , all'interno di onActivityResult
	private final static int FILE_CHOOSER_VIDEO = 49203;//indica la Intent per la scelta della video in locale, all'interno di onActivityResult
	private RadioGroup radio;//RadioButton appartenenti al RadioGroup soprastante per la scelta del tipo di file da cercare o da riprodurre
	private RadioButton rMusic;
	private RadioButton rVideo;
	private ArrayList <MyVideo> items=new ArrayList <MyVideo>() ;//ArrayList in cui salviamo i risultati della query su YouTube
    private ListView list;//ListView in cui visualizziamo i dati salvati precedentemente nell'ArrayList
    private VideoAdapter apt;//Adapter che serve a riempire la ListView
    private static int returnedPos = 0; //Posizione dell'elemento della ListView cliccato
    private EditText d;//TextView dove l'utente può inserire l'url della canzone in streaming o la striga da ricercare su YouTube
    private static String path = "";//percorso del file da riprodurre
    
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		d = (EditText) findViewById(R.id.editText1);
		d.setText("http://");
		list = getListView();
		apt = new VideoAdapter(this, R.id.toptext, items); 
		list.setAdapter(apt);
		
		list.setOnItemClickListener(new ListView.OnItemClickListener() { //Avviamo il video selezionato fra i vari risultati della query visualizzati nella ListView
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				MyVideo mv = items.get(position); //Prendo il video dalla posizione cliccata
				String URL = mv.getUrl();
				/* lo converto in rtsp link lanciando una nuova AsyncTask
				 * la quale prende in ingresso l'URL di youtube e restituisce
				 * un link diretto (rstp link) al file .3gp del video stesso */
				new GetRSTPLink().execute(URL); 				
			}
		});
		
		Button b = (Button) findViewById(R.id.browse);
		Button b1 = (Button) findViewById(R.id.go);
		ChoiceClickListener list = new ChoiceClickListener();
		b.setOnClickListener(list);
		b1.setOnClickListener(list);
		radio = (RadioGroup) findViewById(R.id.radioGroup1);
		rMusic = (RadioButton) findViewById(R.id.radioMusic);
		rVideo = (RadioButton) findViewById(R.id.radioVideo);
		/*
		 * Assegniamo un determinato testo alla TextView al cambiamento dell radio button selezionato
		 */
		rMusic.setOnClickListener(new OnClickListener()
		{
		    @Override
			public void onClick(View arg0)
		    {
				// TODO Auto-generated method stub
				d.setText("http://");
				
			}
		});
		
		rVideo.setOnClickListener(new OnClickListener()
		{
		    @Override
			public void onClick(View arg0)
		    {
				// TODO Auto-generated method stub
		    	d.setText(null);
				d.setHint("Search a video on YouTube");
			}
		});
		
		

	}
	//Implementa l'onClickListener di tutti i pulsanti
	class ChoiceClickListener implements OnClickListener{
	@Override
	public void onClick(View v) {

		if (v.getId() == R.id.browse) {

			int idlevel = radio.getCheckedRadioButtonId();

			if (idlevel == R.id.radioVideo) {
				Intent intent = new Intent(Intent.ACTION_GET_CONTENT); //Attraverso questa intent implicita lanciamo l'activity per cercare il video all'interno del dispositivo è un file audio
				intent.setType("video/*");
				startActivityForResult(intent, FILE_CHOOSER_VIDEO);

			} else {
				Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
				intent.setType("audio/*");
				startActivityForResult(intent, FILE_CHOOSER_MUSIC); //Lanciamo l'activity
			}
		} else if (v.getId() == R.id.go) {
			

			int idlevel = radio.getCheckedRadioButtonId();

			if (idlevel == R.id.radioVideo) {
				EditText d = (EditText) findViewById(R.id.editText1);
				//Se dobbiamo cercare un video facciamo una query a YouTube utilizzando il tag inserito dall'utente
				new GetYoutubeUpdate().execute(d.getText().toString());

			}
			//Se invece dobbiamo riprodurre un Mp3 in remoto prendiamo il link inserito e lo salviamo nell'intent che lancerà l'activity opportuna
			else {

				String URL_song = d.getText().toString();
				Intent intent = new Intent(MediaPlayerActivity.this, Mp3Activity.class);
				intent.putExtra("URL_song", URL_song);
				startActivity(intent);
				
			}

		}

	}
	}



	//permette di far vedere gli oggetti della ListView in base al layout che abbiamo specificato
	private class VideoAdapter extends ArrayAdapter<MyVideo> { 

		/*Lista di video da far visualizzare all'utente*/
		private ArrayList<MyVideo> items;

		public VideoAdapter(Context context, int textViewResourceId,
				ArrayList<MyVideo> items) {
			super(context, textViewResourceId, items);
			this.items = items; 
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			View v = convertView;
			if (v == null) {
				LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
				v = vi.inflate(R.layout.my_listview, null); // <--- Utilizziamo un layout personalizzato
			}
			
			MyVideo c = items.get(position);
			ImageView icon = (ImageView) v.findViewById(R.id.youtubeIcon);
			if (c != null && icon != null) {

				TextView title = (TextView) v.findViewById(R.id.toptext);
				TextView url = (TextView) v.findViewById(R.id.bottomtext);
				title.setText(c.getTitle());
				url.setText(c.getUrl());
				title.setTextSize(url.getTextSize() + 9);
				url.setTextScaleX(1);
				
				returnedPos = position;
			}
			return v;
		}
	}

	//Ogni oggetto MyVideo è composto dal titolo del video e dalla URL
	private class MyVideo {  
		
		String title;
		String url;
		
		public MyVideo(String title, String url) {
			this.title = title;
			this.url = url;
		}
		public String getTitle(){
			return title;
		}
		public String getUrl(){
			return url;
		}
		
	}
	
	/*Gestiamo quale activity lanciare in seguito alla selezione di un file (locale o remoto)*/
	protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
		if (resultCode == RESULT_OK) {
			switch (requestCode) {
			
			
			case FILE_CHOOSER_MUSIC:
				Intent intent = new Intent(MediaPlayerActivity.this,
						Mp3Activity.class);
				String path = data.getDataString();
				intent.putExtra("path", path);
				intent.setData(data.getData());
				startActivity(intent);
				break;

			case FILE_CHOOSER_VIDEO:
				intent = new Intent(MediaPlayerActivity.this,
						VideoActivity.class);
				path = data.getDataString();
				intent.putExtra("path", path);

				startActivity(intent);

			}
		}

	}

	/*Raccolta di oggetti di tipo Video, che contengono informazioni estese sui video da riprodurre*/
	public static class VideoFeed { //Lista di Video
		@Key
		List<Video> items;
		int totalItems;
	}

	public static class Video { //Oggetti completo restituiti dalla query
		@Key
		String title;
		@Key
		String description;
		@Key
		Player player;
		@Key
		DateTime updated;
	}

	public static class Player {
		@Key("default")
		String defaultUrl;
	}
	
	/*Per mezzo di questa classe specifichiamo campi appositi da utilizzare per la ricerca su Youtube*/
	public static class YouTubeUrl extends GenericUrl { 
		@Key //<--- questa annotation serve a specificare che il campo specificato è un campo chiave
		final String alt = "jsonc";
		@Key
		String author;
		@Key
		String q; //<-- query field passato attraverso il costruttore dell'AsyncTask
		@Key("max-results")
		Integer maxResults;

		YouTubeUrl(String url) {
			super(url);
		}
	}
	
    //Aggiorniamo la lista locale con il fee
	public void resfreshList(VideoFeed feed){
		items.clear();		
		if (feed != null)
		for (Video video : feed.items) {
			items.add(new MyVideo(video.title, video.player.defaultUrl));
		}
	}

	/*Asynctask per mezzo della quale viene effettuata la ricerca su Youtube della stringa inserita dall'utente.*/	
	class GetYoutubeUpdate extends AsyncTask<String,Integer,String>{ 

		@Override
		protected String doInBackground(String... statues) { 
			// TODO Auto-generated method stub
			
			/*Classe che astrae il protocollo HTTP, contenuta nella libreria com.google.api.client*/
			HttpTransport transport = new NetHttpTransport();
			
			/*Implementa il pattern di tipo factory per la creazione di un parser Json*/
			final JsonFactory jsonFactory = new JacksonFactory();
			
			/*Il parser Json che utilizziamo per parsare gli elementi*/
			final JsonCParser parser = new JsonCParser(jsonFactory);

			/*Implementa il pattern factory per la creazione di una richiesta Http, utilizzando l'oggetto HttpTransport*/
			HttpRequestFactory factory = transport
					.createRequestFactory(new HttpRequestInitializer() {

						@Override
						public void initialize(HttpRequest request)
								throws IOException {
							// TODO Auto-generated method stub

							/* Si fa in modo che la richiesta HTTP che si sta per inoltrare abbia impostati gli header corretti.
							 * Questi parametri sono forniti dalle documentazioni di Google. 
							 * Successivamente alla HttpRequest viene associato il parser che è stato specificato in precedenza.
							 */
							GoogleHeaders headers = new GoogleHeaders();
							headers.setApplicationName("1Google-YouTubeSample/1.0");
							headers.gdataVersion = "2";
							request.setHeaders(headers);
							request.addParser(parser);
						}
					});
			
			/*Creiamo una nuova YouTubeUrl per la quale specifichiamo il massimo numero di risultati da ritornare, */
			YouTubeUrl url = new YouTubeUrl(
					"https://gdata.youtube.com/feeds/api/videos");
			
			url.maxResults = 20;
			url.q = statues[0]; 
			
			HttpRequest request;
			
				try {
					/*ottengo la HttpRequest dall'oggetto factory, dopodichè mando la richiesta in
					 * esecuzione invocando il metodo .execute(). Ricevo un HttpResponse che viene parsato
					 * in maniera opportuna, restituendo un feed contenente i video che sono il risultato
					 * della query inoltrata.
					 */
					request = factory.buildGetRequest(url);
					VideoFeed feed = request.execute().parseAs(VideoFeed.class);
					resfreshList(feed);
					
					
					
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				

			return null;
		}
		
		@Override
		protected void onPostExecute(String result) {
			// TODO Auto-generated method stub
			super.onPostExecute(result);
			/*notifico l'avvenuto aggiornamento*/
			apt.notifyDataSetChanged();
		}
		
	}
	//Funzione di comodo che ha lo scopo di parsare il classico URL di un video su Youtube e restituire l'id
	protected static String extractYoutubeId(String url) 
			throws MalformedURLException {
		String id = null;
		try {
			String query = new URL(url).getQuery();
			if (query != null) {
				String[] param = query.split("&");
				for (String row : param) {
					String[] param1 = row.split("=");
					if (param1[0].equals("v")) {
						id = param1[1];
					}
				}
			} else {
				if (url.contains("embed")) {
					id = url.substring(url.lastIndexOf("/") + 1);
				}
			}
		} catch (Exception ex) {
			Log.e("Exception", ex.toString());
		}
		return id;
	}
	
	
	/* Per mezzo di questo AsyncTask è possibile, partendo da un URL di Youtube, ottenere un link rstp, ovvero un link diretto al file video.
	 * Per poter ottenere questo risultato viene effettuata una semplice HTTP Request, utilizzando un apposito web service che, dato uno
	 * Youtube Id, restituisce un file .XML contenente informazioni circa quel video. 
	 * All'interno di questo XML, è possibile identificare il tag <media:content> che contiene l'indirizzo desiderato. 
	 */
	class GetRSTPLink extends AsyncTask<String, Integer, String> { 				

		@Override
		protected String doInBackground(String... str) {
			String urlYoutube = null;
			try {
				urlYoutube = str[0];
				String gdy = "http://gdata.youtube.com/feeds/api/videos/"; //URL di base
				//Ottengo una istanza della classe Document dal file XML
				DocumentBuilder documentBuilder = DocumentBuilderFactory
						.newInstance().newDocumentBuilder();
				//Estraggo lo Youtube ID dall'URL
				String id = extractYoutubeId(urlYoutube);
				//Compongo l'URL desiderato aggiungendo l'ID del video a quello di base
				URL url = new URL(gdy + id);
				//Creo una nuova connessione
				HttpURLConnection connection = (HttpURLConnection) url
						.openConnection();
				
				/*Parso tutti gli elementi del documento, a partire dalla radice fornita dall'oggetto di tipo Document, alla ricerca
				 * del nodo che contiene la tag "media:content"*/
				Document doc = documentBuilder.parse(connection
						.getInputStream());
				Element el = doc.getDocumentElement();
				
				//Prendo tutti gli elementi che hanno tag "media:content", in questo caso sono più di uno per ogni video
				NodeList list = el.getElementsByTagName("media:content");// /media:content
				
				String cursor = urlYoutube; //<-- in caso di fallimento restituisco nuovamente il link originale
				
				/*scorro tutti gli elementi, per ognuno di essi verifico che sia presente un Url di tipo rstp e che il formato sia di tipo 
				 * 1, che è quello di nostro interesse. Per completezza, i formati sono
				 *     1 - RTSP streaming URL for mobile video playback. H.263 video (up to 176x144) and AMR audio.
    				   5 - HTTP URL to the embeddable player (SWF) for this video. This format is not available for a video that is not embeddable. Developers commonly add &format=5 to their queries to restrict results to videos that can be embedded on their sites.
    				   6 - RTSP streamingURL for mobile video playback. MPEG-4 SP video (up to 176x144) and AAC audio.
				 */
				for (int i = 0; i < list.getLength(); i++) {
					Node node = list.item(i);
					if (node != null) {
						NamedNodeMap nodeMap = node.getAttributes();
						HashMap<String, String> maps = new HashMap<String, String>();
						for (int j = 0; j < nodeMap.getLength(); j++) {
							Attr att = (Attr) nodeMap.item(j);
							maps.put(att.getName(), att.getValue());
						}
						if (maps.containsKey("yt:format")) {
							String f = maps.get("yt:format");
							if (maps.containsKey("url")) {
								cursor = maps.get("url");
							}
							if (f.equals("1"))
								return cursor;
						}
					}
				}
				return cursor;
			} catch (Exception ex) {
				Log.e("Get Url Video RTSP Exception======>>", ex.toString());
			}
			return urlYoutube;
		}

		@Override
		protected void onPostExecute(String result) {
			// TODO Auto-generated method stub
			super.onPostExecute(result);
			path = result;
			if (path != null) {
				Intent videoP = new Intent(MediaPlayerActivity.this,
						VideoActivity.class);
				

				videoP.putExtra("path", path);
				startActivity(videoP);
			}

		}

	}
	

}